package com.lq.learningTest.fanxing;

public class Array <T> implements Super<T>{
    //维护一个数组,要想什么都存，就要使用顶级父类
    private Object[] array;
    // 数组存储数据的长度，默认开始是0
    private int size;
    // 数组当前的容量
    private int capacity;

    //构造器之间的调用
    public Array(){
        this(10);
    }
    //构造器的重载
    public Array(int capacity){
        this.array = new Object[capacity];
        this.capacity = capacity;
    }

    //添加数据的方法,默认是尾插
    @Override
    public void add(T data){
        // 确保容量足够,如果容量不够就扩容
        ensureCapacity(this.size + 1);
        this.array[this.size++] = data;//这里记住是添加了数据之后再长度自增，因为数组尾部数据的下标比数组长度少一
    }

    //添加数据的方法，指定下标添加
    @Override
    public boolean add(int index,T data){
        ensureCapacity(this.size + 1);
        /**
         * Object src : 原数组
         * int srcPos : 从元数据的起始位置开始
         * Object dest : 目标数组
         * int destPos : 目标数组的开始起始位置
         * int length  : 要copy的数组的长度
         */
        // index以后的数据统一向后移动，空出位置
        System.arraycopy(this.array, index, this.array, index + 1,
                this.size - index);
        this.array[index] = data;
        this.size ++;
        return true;
    }

    //指定下标删除数据，删除成功返回删除的值，否则返回空
    @Override
    public T remove(int index) {
        //验证下标是否符合规范
        if(rangeCheck(index)){
            T res = (T) this.array[index];
            /**
             * Object src : 原数组
             * int srcPos : 从元数据的起始位置开始
             * Object dest : 目标数组
             * int destPos : 目标数组的开始起始位置
             * int length  : 要copy的数组的长度
             */
            System.arraycopy(this.array, index+1, this.array, index, this.size-index);
            this.size--;
            return res;
        }
        return null;
    }

    //指定下标修改数据
    @Override
    public boolean set(int index,T data) {
        //验证下标是否符合规范
        if(rangeCheck(index)){
            this.array[index] = data;
            return true;
        }
        return false;
    }

    /*根据下标查询数字,因为查询的数字可以是任何数值又或者是没有，所以这里用int的包装类，因为从基础数据类型到引用数据类型的
    转变，所以没查到数据的时候可以返回null,查到数据的时候就返回数值*/
    @Override
    public T get(int index){
        if(rangeCheck(index)){
            return (T) this.array[index];
        }
        return null;
    }

    //查看当前有多少个数字
    @Override
    public int size(){
        return this.size;//注意这里使用的是实例的成员变量不是类的成员变量，因为不用的实例对应的值可能不同
    }

    // 确保容量，并在需要的时候扩容,这里是执行函数而不是判断函数，因为无论需要的空间与实际的容量大小如何都必须要设置成合适容量内
    private void ensureCapacity(int needCapacity) {
        if (needCapacity > this.capacity){
            //容量增加了1.5倍
            this.capacity = this.capacity + (this.capacity >> 1);
            Integer[] newArray = new Integer[this.capacity];
            /**
             * Object src : 原数组
             * int srcPos : 从元数据的起始位置开始
             * Object dest : 目标数组
             * int destPos : 目标数组的开始起始位置
             * int length  : 要copy的数组的长度
             */
            System.arraycopy(this.array, 0, newArray, 0, this.array.length);
            this.array = newArray;//旧数组首地址指向新数组首地址，旧数组内容被jvm垃圾回收机制回收
        }
    }

    //验证下标是否合法
    private boolean rangeCheck(int index) {
        //只要有一个不满足就返回false
        return index <= this.size-1 && index >= 0;
    }
}
